# from log import Log
# from logging import Logger
import math
import random
from enum import Enum


# import pandas as pd
# import numpy as np

class DelayType(Enum):
    instant = 0
    certain = 1
    exp = 2
    uniform = 3

    def __str__(self):
        match self:
            case DelayType.instant:
                return "instant"
            case DelayType.certain:
                return "certain"
            case DelayType.exp:
                return "exp"
            case DelayType.uniform:
                return "uniform"

class Delay:
    def __init__(self, delay: str | DelayType, *params) -> None:
        if isinstance(delay, str):
            match delay:
                case "instant":
                    self.delay = DelayType.instant
                case "certain":
                    self.delay = DelayType.certain
                case "exp":
                    self.delay = DelayType.exp
                case "uniform":
                    self.delay = DelayType.uniform
                case _:
                    raise ValueError("Invalid delay type")
        elif isinstance(delay, DelayType):
            self.delay = delay
        else:
            raise ValueError("Invalid delay type")
        self.params = params
    
    def __str__(self):
        return f"{self.delay}{self.params}" if self.params else str(self.delay)

    def generate_delay(self) -> float:
        match self.delay:
            case DelayType.instant:
                return 0.0
            case DelayType.certain:
                if len(self.params) != 1:
                    raise ValueError("Invalid parameters for certain delay")
                else:
                    return self.params[0]
            case DelayType.exp:
                if len(self.params) != 1:
                    raise ValueError("Invalid parameters for exp delay")
                else:
                    delta = random.random()
                    return -math.log(delta) * self.params[0]
            case DelayType.uniform:
                if len(self.params) != 2:
                    raise ValueError("Invalid parameters for uniform delay")
                else:
                    return random.uniform(self.params[0], self.params[1])
            case _:
                raise ValueError("Invalid delay type")
    
    def input_delay(self) -> float:
        match self.delay:
            case DelayType.instant:
                print("Instant delay")
                return 0.0
            case DelayType.certain:
                if len(self.params) != 1:
                    raise ValueError("Invalid parameters for certain delay")
                else:
                    print("certain delay is %s" % self.params[0])
                    return self.params[0]
            case DelayType.exp:
                if len(self.params) != 1:
                    raise ValueError("Invalid parameters for exp delay")
                else:
                    delay = float(input("Please input a positive delay for exp delay: "))
                    if delay <= 0:
                        raise ValueError("Delay must be positive")
                    return delay
            case DelayType.uniform:
                if len(self.params) != 2:
                    raise ValueError("Invalid parameters for uniform delay")
                else:
                    delay = float(input("Please input a positive delay for uniform delay: "))
                    if delay <= 0:
                        raise ValueError("Delay must be positive")
                    return delay
            case _:
                raise ValueError("Invalid delay type")
        

# def test_exp_delay():
#     delay = Delay("exp", 2.0)
#     nums = 1000
#     # delay_dataframe = pd.DataFrame({"delay": [delay.generate_delay() for _ in range(nums)]})
#     delay_dataframe = np.array([delay.generate_delay() for _ in range(nums)])
#     import matplotlib.pyplot as plt
#     plt.hist(delay_dataframe,density=True)

if __name__ == "__main__":
    print(Delay("instant").generate_delay())
    print(Delay("certain", 2.0).generate_delay())
    print(Delay("exp", 2.0).generate_delay())
    print(Delay("uniform", 0.0, 10.0).generate_delay())
    for i in range(10):
        print(Delay("exp", 50*365*24*60*60).generate_delay())
    # test_exp_delay()
